package com.hbzhit.common.ueditor;

import cn.hutool.core.io.resource.ResourceUtil;
import com.hbzhit.common.ueditor.define.ActionMap;
import org.json.JSONArray;
import org.json.JSONObject;

import java.io.*;
import java.util.HashMap;
import java.util.Map;

/**
 * 配置管理器
 * @author hancong03@baidu.com
 *
 */
public final class ConfigManager {

	//项目前缀
	private String projectName;

	//上传文件基本路径
	private final String basePath;

	private final String rootPath;
	private final String originalPath;
	private final String contextPath;
	private String parentPath = null;
	private JSONObject jsonConfig = null;

	// 涂鸦上传filename定义
	private final static String SCRAWL_FILE_NAME = "scrawl";

	// 远程图片抓取filename定义
	private final static String REMOTE_FILE_NAME = "remote";


	/*
	 * 通过一个给定的路径构建一个配置管理器， 该管理器要求地址路径所在目录下必须存在config.properties文件
	 */
	private ConfigManager ( String rootPath, String projectName, String contextPath, String uri ,String basePath) throws FileNotFoundException, IOException {

		this.projectName = projectName;
		this.basePath = basePath;

		rootPath = rootPath.replace( "\\", "/" );

		this.rootPath = rootPath;
		this.contextPath = contextPath;

		if ( contextPath.length() > 0 ) {
			this.originalPath = this.basePath + this.rootPath + uri.substring( contextPath.length() );
		} else {
			this.originalPath = this.basePath + this.rootPath + uri;
		}
		this.initEnv();
	}

	/**
	 * 配置管理器构造工厂
	 * @param rootPath UEditor根路径
	 * @param projectName 项目名称
	 * @param contextPath 服务器所在项目路径
	 * @param uri 当前访问的uri
	 * @param basePath 服务器基础路径
	 * @return 配置管理器实例或者null
	 */
	public static ConfigManager getInstance ( String rootPath, String projectName, String contextPath, String uri ,String basePath) {

		try {
			return new ConfigManager(rootPath, projectName, contextPath, uri,basePath);
		} catch ( Exception e ) {
			return null;
		}

	}

	// 验证配置文件加载是否正确
	public boolean valid () {
		return this.jsonConfig != null;
	}

	public JSONObject getAllConfig () {

		return this.jsonConfig;

	}

	public Map<String, Object> getConfig ( int type ) throws Exception {

		Map<String, Object> conf = new HashMap<String, Object>();
		String savePath = null;

		switch ( type ) {

			case ActionMap.UPLOAD_FILE:
				conf.put( "isBase64", "false" );
				conf.put( "maxSize", this.jsonConfig.getLong( "fileMaxSize" ) );
				conf.put( "allowFiles", this.getArray( "fileAllowFiles" ) );
				conf.put( "fieldName", this.jsonConfig.getString( "fileFieldName" ) );
				savePath = this.jsonConfig.getString( "filePathFormat" );
				break;

			case ActionMap.UPLOAD_IMAGE:
				conf.put( "isBase64", "false" );
				conf.put( "maxSize", this.jsonConfig.getLong( "imageMaxSize" ) );
				conf.put( "allowFiles", this.getArray( "imageAllowFiles" ) );
				conf.put( "fieldName", this.jsonConfig.getString( "imageFieldName" ) );
				savePath = this.jsonConfig.getString( "imagePathFormat" );
				break;

			case ActionMap.UPLOAD_VIDEO:
				conf.put( "maxSize", this.jsonConfig.getLong( "videoMaxSize" ) );
				conf.put( "allowFiles", this.getArray( "videoAllowFiles" ) );
				conf.put( "fieldName", this.jsonConfig.getString( "videoFieldName" ) );
				savePath = this.jsonConfig.getString( "videoPathFormat" );
				break;

			case ActionMap.UPLOAD_SCRAWL:
				conf.put( "filename", ConfigManager.SCRAWL_FILE_NAME );
				conf.put( "maxSize", this.jsonConfig.getLong( "scrawlMaxSize" ) );
				conf.put( "fieldName", this.jsonConfig.getString( "scrawlFieldName" ) );
				conf.put( "isBase64", "true" );
				savePath = this.jsonConfig.getString( "scrawlPathFormat" );
				break;

			case ActionMap.CATCH_IMAGE:
				conf.put( "filename", ConfigManager.REMOTE_FILE_NAME );
				conf.put( "filter", this.getArray( "catcherLocalDomain" ) );
				conf.put( "maxSize", this.jsonConfig.getLong( "catcherMaxSize" ) );
				conf.put( "allowFiles", this.getArray( "catcherAllowFiles" ) );
				conf.put( "fieldName", this.jsonConfig.getString( "catcherFieldName" ) + "[]" );
				savePath = this.jsonConfig.getString( "catcherPathFormat" );
				break;

			case ActionMap.LIST_IMAGE:
				conf.put( "allowFiles", this.getArray( "imageManagerAllowFiles" ) );
				conf.put( "dir", this.jsonConfig.getString( "imageManagerListPath" ) );
				conf.put( "count", this.jsonConfig.getInt( "imageManagerListSize" ) );
				break;

			case ActionMap.LIST_FILE:
				conf.put( "allowFiles", this.getArray( "fileManagerAllowFiles" ) );
				conf.put( "dir", this.jsonConfig.getString( "fileManagerListPath" ) );
				conf.put( "count", this.jsonConfig.getInt( "fileManagerListSize" ) );
				break;
			default:
				break;
		}

		/* 将basePath塞进conf */
		conf.put("basePath", basePath);
		conf.put("rootPath", this.rootPath );
		conf.put("projectName", projectName);
		conf.put("contextPath", contextPath);
		conf.put("savePath", savePath );

		return conf;

	}

	private void initEnv () throws FileNotFoundException, IOException {

		File file = new File( this.originalPath );

		if ( !file.isAbsolute() ) {
			file = new File( file.getAbsolutePath() );
		}

		this.parentPath = file.getParent();

		// String configContent = this.readFile( this.getConfigPath() );

		try{
			JSONObject jsonConfig = new JSONObject();
			/* 基础配置 */
			//基本路径
			jsonConfig.put("basePath", basePath);
			//项目前缀
			jsonConfig.put("projectName", projectName);
			//项目路径
			jsonConfig.put("contextPath", contextPath);

			/* 上传图片配置项 */
			//动作名称
			jsonConfig.put("imageActionName", "uploadimage");
			//表单名称
			jsonConfig.put("imageFieldName", "upfile");
			//格式显示
			jsonConfig.put("imagePathFormat", "/image/{yyyy}{mm}{dd}/{time}{rand:6}");
			//访问路径前缀
			jsonConfig.put("imageUrlPrefix", "");
			//最大体积
			jsonConfig.put("imageMaxSize", 51200000);
			//浮动方式
			jsonConfig.put("imageInsertAlign", "none");
			//格式支持
			jsonConfig.put("imageAllowFiles", new JSONArray(new String[]{".png", ".jpg", ".jpeg", ".gif", ".bmp"}));
			//是否压缩图片
			jsonConfig.put("imageCompressEnable", true);
			//图片压缩最长边限制
			jsonConfig.put("imageCompressBorder", 1600);

			/* 涂鸦图片上传配置项 */
			//动作名称
			jsonConfig.put("scrawlActionName", "uploadscrawl");
			//表单名称
			jsonConfig.put("scrawlFieldName", "upfile");
			//格式显示
			jsonConfig.put("scrawlPathFormat", "/scrawl/{yyyy}{mm}{dd}/{time}{rand:6}");
			//访问路径前缀
			jsonConfig.put("scrawlUrlPrefix", "");
			//最大体积
			jsonConfig.put("scrawlMaxSize", 51200000);
			//浮动方式
			jsonConfig.put("scrawlInsertAlign", "none");

			/* 截图工具上传 */
			//动作名称
			jsonConfig.put("snapscreenActionName", "uploadimage");
			//格式显示
			jsonConfig.put("snapscreenPathFormat", "/snapscreen/{yyyy}{mm}{dd}/{time}{rand:6}");
			//访问路径前缀
			jsonConfig.put("snapscreenUrlPrefix", "");
			//浮动方式
			jsonConfig.put("snapscreenInsertAlign", "none");

			/* 抓取远程图片配置 */
			//动作名称
			jsonConfig.put("catcherActionName", "catchimage");
			//表单名称
			jsonConfig.put("catcherFieldName", "source");
			//格式显示
			jsonConfig.put("catcherPathFormat", "/catcher/{yyyy}{mm}{dd}/{time}{rand:6}");
			//访问路径前缀
			jsonConfig.put("catcherUrlPrefix", "");
			//最大体积
			jsonConfig.put("catcherMaxSize", 2048000);
			//格式支持
			jsonConfig.put("catcherAllowFiles", new JSONArray(new String[]{".png", ".jpg", ".jpeg", ".gif", ".bmp"}));
			//域名/IP配置
			jsonConfig.put("catcherLocalDomain", new JSONArray(new String[]{"127.0.0.1", "localhost", "img.baidu.com"}));

			/* 上传视频配置 */
			//动作名称
			jsonConfig.put("videoActionName", "uploadvideo");
			//表单名称
			jsonConfig.put("videoFieldName", "upfile");
			//格式显示
			jsonConfig.put("videoPathFormat", "/video/{yyyy}{mm}{dd}/{time}{rand:6}");
			//访问路径前缀
			jsonConfig.put("videoUrlPrefix", "");
			//最大体积
			jsonConfig.put("videoMaxSize", 1024000000);
			//格式支持
			jsonConfig.put("videoAllowFiles", new JSONArray(new String[]{".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid"}));

			/* 上传文件配置 */
			jsonConfig.put("fileActionName", "uploadfile");
			//表单名称
			jsonConfig.put("fileFieldName", "upfile");
			//格式显示
			jsonConfig.put("filePathFormat", "/file/{yyyy}{mm}{dd}/{time}{rand:6}");
			//访问路径前缀
			jsonConfig.put("fileUrlPrefix", "");
			//最大体积
			jsonConfig.put("fileMaxSize", 51200000);
			//格式支持
			jsonConfig.put("fileAllowFiles", new JSONArray(new String[]{
				".png", ".jpg", ".jpeg", ".gif", ".bmp",
				".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
				".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
				".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
				".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"
			}));

			/* 列出指定目录下的图片 */
			//动作名称
			jsonConfig.put("imageManagerActionName", "listimage");
			//列表路径
			jsonConfig.put("imageManagerListPath", "/image/");
			//列表大小（行数）
			jsonConfig.put("imageManagerListSize", 20);
			//访问路径前缀
			jsonConfig.put("imageManagerUrlPrefix", "");
			//格式支持
			jsonConfig.put("imageManagerAllowFiles", new JSONArray(new String[]{".png", ".jpg", ".jpeg", ".gif", ".bmp"}));
			//浮动方式
			jsonConfig.put("imageManagerInsertAlign", "none");

			/* 列出指定目录下的文件 */
			//动作名称
			jsonConfig.put("fileManagerActionName", "listfile");
			//列表路径
			jsonConfig.put("fileManagerListPath", "/file/");
			//列表大小（行数）
			jsonConfig.put("fileManagerListSize", 20);
			//访问路径前缀
			jsonConfig.put("fileManagerUrlPrefix", "");
			//格式支持
			jsonConfig.put("fileManagerAllowFiles", new JSONArray(new String[]{
				".png", ".jpg", ".jpeg", ".gif", ".bmp",
				".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
				".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
				".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
				".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"
			}));
			this.jsonConfig = jsonConfig;
		} catch ( Exception e ) {
			this.jsonConfig = null;
		}

	}

	private String getConfigPath () {
		//return this.parentPath + File.separator + ConfigManager.configFileName;
		/*=========手动修改部分=========*/
		try{
			//获取classpath下的config.json路径
			return ResourceUtil.getResource("ueditor-config.json").getPath();
		}catch (Exception e){
			e.printStackTrace();
			return null;
		}
	}

	private String[] getArray ( String key ) throws Exception {

		JSONArray jsonArray = this.jsonConfig.getJSONArray( key );
		String[] result = new String[ jsonArray.length() ];

		for ( int i = 0, len = jsonArray.length(); i < len; i++ ) {
			result[i] = jsonArray.getString( i );
		}

		return result;

	}

	private String readFile ( String path ) throws IOException {

		StringBuilder builder = new StringBuilder();

		try {

			InputStreamReader reader = new InputStreamReader( new FileInputStream( path ), "UTF-8" );
			BufferedReader bfReader = new BufferedReader( reader );

			String tmpContent = null;

			while ( ( tmpContent = bfReader.readLine() ) != null ) {
				builder.append( tmpContent );
			}

			bfReader.close();

		} catch ( UnsupportedEncodingException e ) {
			// 忽略
		}

		return this.filter( builder.toString() );

	}

	// 过滤输入字符串, 剔除多行注释以及替换掉反斜杠
	private String filter ( String input ) {

		return input.replaceAll( "/\\*[\\s\\S]*?\\*/", "" );

	}

}
